const path = require('path');
const { Listr } = require('listr2');
const cli = require('pixl-cli');
const boxen = require('boxen');


const processors = {
    codeClass: require('./processor/code-class'),
};

const TEMPLATE_DEFS = {
    "repo": {
        name: "Spring MyBatis Repository",
        desc: "基于 MyBatis-plus 的数据实体和相关配套代码模板",
        comment: "JDK 1.8 / Maven",
        type: "java",
        subTasks: processors.codeClass.javaClassGenSubTasks,
        preBuildProcess: processors.codeClass.javaClassPreProcess,
        buildProcess: processors.codeClass.javaRepoProcess,
    },
    "crud": {
        name: "Ugeez CRUD",
        desc: "基于 Ugeez Java 工程结构的CRUD代码，包括Entity/DAO/DTO/Service/Controller",
        comment: "JDK 1.8 / Maven",
        type: "java",
        subTasks: processors.codeClass.javaClassGenSubTasks,
        preBuildProcess: processors.codeClass.javaClassPreProcess,
        buildProcess: processors.codeClass.javaCRUDProcess,
    },
    "data2crud": {
        name: "Ugeez Data to CRUD",
        desc: "根据MyBatis的数据实体类，反向生成基于 Ugeez Java 工程结构的CRUD代码，包括Entity/DAO/DTO/Service/Controller",
        comment: "JDK 1.8 / Maven",
        type: "java",
        subTasks: processors.codeClass.javaClassGenSubTasks_data2crud,
        preBuildProcess: undefined,
        buildProcess: processors.codeClass.javaData2CRUDProcess,
    },
    "class2type": {
        name: "Java class to TS type",
        desc: "指定Java类文件，生成Typescript类型",
        comment: "JDK 1.8 / Maven",
        type: "java",
        subTasks: processors.codeClass.javaClassGenSubTasks_class2type,
        preBuildProcess: undefined,
        buildProcess: processors.codeClass.javaClass2TypeProcess,
    },
    "api2sdk": {
        name: "Spring Controller to TS types/services",
        desc: "指定Spring Controller(接口)文件，生成对应的Typescript类型和接口SDK",
        comment: "JDK 1.8 / Maven",
        type: "java",
        subTasks: processors.codeClass.javaClassGenSubTasks_api2sdk,
        preBuildProcess: undefined,
        buildProcess: processors.codeClass.javaApi2sdkProcess,
    },
    "type2crudui": {
        name: "Typescript Type to CRUD reactjs page",
        desc: "指定Typescript文件和目标Type，生成对应的CRUD reactjs页面文件，包括列表页/创建页/详情页",
        comment: "JDK 1.8 / Maven",
        type: "typescript",
        subTasks: processors.codeClass.tsGenSubTasks_type2crudui,
        preBuildProcess: undefined,
        buildProcess: processors.codeClass.tsType2cruduiProcess,
    }
};

const TEMPLATES = [
    ["Type", "Name", "Description", "Requirement"],
    // [ "1", "Spring Cloud Project", "基于 ugeez-commons 的 Spring Cloud 工程模板", "" ],
];

(() => {
    let temps = [];
    for (let key in TEMPLATE_DEFS) {
        let def = TEMPLATE_DEFS[key];
        temps.push([key, def.name, def.desc, def.comment || ""]);
    }
    temps = temps.sort((a, b) => Number(a[1]) > Number(a[2]));
    TEMPLATES.push.apply(TEMPLATES, temps);
})();

const findTemplate = (noOrName) => {
    for (let i = 1; i < TEMPLATES.length; i++) {
        if (TEMPLATES[i][0] == noOrName || TEMPLATES[i][1] == noOrName) return TEMPLATE_DEFS[TEMPLATES[i][0]];
    }
    return undefined;
}

exports.exec = function (runArgs, done) {
    let dir = process.cwd();
    let template = undefined;
    let templateDef;

    let ARGS = {};
    runArgs.forEach(function (val, i) {
        if (val.startsWith("--")) {
            let temp = val.split("=");
            ARGS[temp[0].substring(2)] = temp[1] == undefined ? true : temp[1];
        }
    });

    template = ARGS['template'];

    let pdir = path.join(dir, '');

    let run = () => {

        const tasks = [
            {
                title: 'choose a template for creating codes ---> ' + templateDef.name,
                task: async (ctx, task) => {
                    for (let key in ARGS) {
                        ctx[key] = ARGS[key];
                    }

                    ctx.pdir = pdir;
                    ctx.template = template;
                    ctx.templateDef = templateDef;

                    if (templateDef.preBuildProcess) {
                        await templateDef.preBuildProcess(ctx, task);
                    }
                }
            },
            {
                title: 'configuration',
                task: (ctx, task) => {
                    if (templateDef.subTasks) {
                        return task.newListr(templateDef.subTasks(ctx, task));
                    } else {
                        return new Promise(resolve => resolve());
                    }
                }
            },
            {
                title: 'create codes',
                task: async (ctx, task) => {
                    if (templateDef.buildProcess) {
                        await templateDef.buildProcess(ctx, task);
                    }
                }
            },
        ];


        new Listr(tasks, { concurrent: false }).run().then(() => {
            setTimeout(() => {
                console.log(boxen('create codes successfully!', { padding: 1, borderStyle: 'classic' }));
            }, 100);
        }).catch(err => {
            console.error(err);
        });
    }

    let chooseTemplate = (callBack) => {
        cli.prompt("Which codes your want to create?\n" + cli.table([...TEMPLATES]) + "\nchoose > ", "", (noOrName) => {
            // cli.print("Hello " + name + "!\n");
            templateDef = findTemplate(noOrName);
            if (!templateDef) {
                cli.warn("Invalid codes choose. Please input the correct type or Name.\n");
                return setTimeout(() => {
                    chooseTemplate();
                }, 1000);
            }
            callBack && callBack();
        });
    }

    chooseTemplate(() => run());

}